/*
pub enum Lhaist {
    Empty,
    Elem(i32, Box<List>)
}
*/

use std::fmt::Display;
use std::mem;

#[derive(Debug)]
pub struct List<T> {
    // 不能是pub，否则也会报错。
    head: Link<T>,
}

type Link<T> = Option<Box<Node<T>>>;

impl<T: Display> List<T> {
    pub fn new() -> Self {
        List { head: None }
    }

    pub fn push(&mut self, elem: T) {
		let new_node = Box::new(Node {
			elem: elem,
			next: self.head.take(), // take 可以将原值转换为None
		});

		self.head = Some(new_node);
    }

    pub fn pop(&mut self) -> Option<T> {
		match self.head.take() {
			None => None,
			Some(node) => {
				self.head = node.next;
				Some(node.elem)
			}
		}
    }

    pub fn dump(&self) -> usize {
        let mut start = &self.head;
        let mut count = 0_usize;

        loop {
            match start {
                None => {
                    println!("ends");
                    break;
                },
                Some(n) => {
                    count += 1;
                    println!("result is: {}", n.elem);
                    start = &n.next;
                }
            }
        }
        count
    }
}

#[derive(Debug)]
struct Node<T> {
    elem: T,
    next: Link<T>,
}

impl<T> Drop for List<T> {
    fn drop(&mut self) {
        // 让引用减1.
        let mut cur_link = self.head.take();
        while let Some(mut boxed_node) = cur_link {
            cur_link = boxed_node.next.take();
        }
    }
}

#[test]
fn test_link() {
    let mut l = List::new();
    l.push(5_i32);
    l.push(8_i32);
    l.dump();
	assert_eq!(l.pop(), Some(8));
	assert_eq!(l.pop(), Some(5));
	assert_eq!(l.pop(), None);

}
